home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / mailconf / alias.c < prev    next >
C/C++ Source or Header  |  1996-07-25  |  11KB  |  511 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include <limits.h>
  6. #include <sys/stat.h>
  7. #include "mailconf.h"
  8. #include "internal.h"
  9. #include "../misc/misc.h"
  10. #include "../dialog/dialog.h"
  11. #include "../userconf/userconf.h"
  12. #include "../netconf/netconf.h"
  13. #include "../paths.h"
  14. #include "mailconf.m"
  15.  
  16. static MAILCONF_HELP_FILE help_aliases("aliases");
  17.  
  18. static CONFIG_FILE f_aliases (ETC_ALIASES,help_aliases
  19.     ,CONFIGF_MANAGED|CONFIGF_OPTIONNAL);
  20.  
  21.  
  22. class ALIAS: public ARRAY_OBJ{
  23.     SSTRING name;
  24.     SSTRINGS values;
  25.     SSTRING comment;
  26.     SSTRING filter;
  27.     SSTRING file;
  28.     /*~PROTOBEG~ ALIAS */
  29. public:
  30.     ALIAS (char *line);
  31.     ALIAS (void);
  32. private:
  33.     void addoneval (const char *val);
  34. public:
  35.     int edit (void);
  36.     int file_ok (void);
  37.     int filter_ok (void);
  38.     const char *getname (void);
  39.     int is_valid (void);
  40. private:
  41.     void splitline (char *ptpt);
  42. public:
  43.     void write (FILE *fout);
  44.     /*~PROTOEND~ ALIAS */
  45. };
  46.  
  47.  
  48. PUBLIC ALIAS::ALIAS()
  49. {
  50. }
  51.  
  52. static char *str_copyupto (char *dest, const char *src, char stop)
  53. {
  54.     while (isgraph(*src) && *src != stop) *dest++ = *src++;
  55.     *dest = '\0';
  56.     return ((char*) src);
  57. }
  58.  
  59. /*
  60.     Add one element of the alias list
  61. */
  62. PRIVATE void ALIAS::addoneval(const char *val)
  63. {
  64.     char *pt = str_skip (val);
  65.     if (pt[0] == '|'){
  66.         pt++;
  67.         filter.setfrom (str_skip(pt));
  68.     }else if (strncmp(val,":include:",9)==0){
  69.         file.setfrom(val+9);
  70.     }else{
  71.         values.add (new SSTRING(val));
  72.     }
  73. }
  74.  
  75. /*
  76.     Parse an alias list
  77. */
  78. PRIVATE void ALIAS::splitline(char *ptpt)
  79. {
  80.     /* #Specification: mailconf / alias / limits
  81.         We assume that an alias list has at most
  82.         one command redirection and one include file.
  83.         It may have as many other element (email address)
  84.         as needed.
  85.     */
  86.     while (1){
  87.         ptpt = str_skip (ptpt);
  88.         if (ptpt[0] == '\0'){
  89.             break;
  90.         }else if (ptpt[0] == ','){
  91.             ptpt++;
  92.         }else if (ptpt[0] == '"'){
  93.             char word[200];
  94.             ptpt++;
  95.             char *ptw = word;
  96.             while (*ptpt != '\0' && *ptpt != '"') *ptw++ = *ptpt++;
  97.             *ptw = '\0';
  98.             if (*ptpt == '"') ptpt++;
  99.             addoneval (word);
  100.         }else{
  101.             char word[200];
  102.             ptpt = str_copyupto (word,ptpt,',');
  103.             addoneval(word);
  104.         }
  105.     }
  106. }
  107.  
  108. /*
  109.     Used when reading the /etc/aliases file
  110.  
  111.     line will be trashed.
  112. */
  113. PUBLIC ALIAS::ALIAS(char *line)
  114. {
  115.     char *pt = str_skip(line);
  116.     if (pt[0] == '#'){
  117.         comment.setfrom (pt);
  118.     }else{
  119.         char *ptpt = strchr(pt,':');
  120.         if (ptpt != NULL){
  121.             *ptpt++ = '\0';
  122.             strip_end (pt);
  123.             name.setfrom (pt);
  124.             splitline (ptpt);
  125.         }
  126.     }
  127. }
  128.  
  129. PUBLIC const char *ALIAS::getname()
  130. {
  131.     return name.get();
  132. }
  133.  
  134. PUBLIC int ALIAS::filter_ok()
  135. {
  136.     if (!filter.is_empty()){
  137.         /* #Specification: mailconf / aliases / filter program
  138.             Linuxconf assumes the first word of the filter part of an
  139.             alias is the program name (with or without path). It will
  140.             check if the path exist either as is, or in /bin or /usr/bin.
  141.  
  142.             It will send a warning if the program can't be found.
  143.             Complex script can be entered here and linuxconf may be
  144.             fooled by this. It will just print a warning anyway
  145.             and the alias will be accepted.
  146.  
  147.             If the program can be located, linuxconf will check that
  148.             it is indeed executable.
  149.         */
  150.         char prog[PATH_MAX],binprog[PATH_MAX],usrbinprog[PATH_MAX];
  151.         str_copyword(prog,filter.get());
  152.         sprintf (binprog,"/bin/%s",prog);
  153.         sprintf (usrbinprog,"/usr/bin/%s",prog);
  154.         struct stat st;
  155.         if (stat (prog,&st) == -1
  156.             && stat (binprog,&st) == -1
  157.             && stat (usrbinprog,&st) == -1){
  158.             xconf_notice (MSG_U(N_MISSING,"%s does not exist"),prog);
  159.         }else if ((st.st_mode & 0111)==0){
  160.             xconf_notice (MSG_U(N_NOEXEC,"%s is not executable"));
  161.         }
  162.     }
  163.     return 1;
  164. }
  165. PUBLIC int ALIAS::file_ok()
  166. {
  167.     /* #Specification: mailconf / aliases / in a file
  168.         When the user specify the indirect file for aliases
  169.         mailconf check if the file exist and send a notice
  170.         to the user if this is not the case. The
  171.         operation is accepted anyway.
  172.     */
  173.     if (!file.is_empty()){
  174.         if (!file_exist(file.get())){
  175.             xconf_notice (MSG_R(N_MISSING),file.get());
  176.         }
  177.     }
  178.     return 1;
  179. }
  180.  
  181. /*
  182.     Write one record
  183. */
  184. PUBLIC void ALIAS::write (FILE *fout)
  185. {
  186.     if (!name.is_empty()){
  187.         fprintf (fout,"%s: ",name.get());
  188.         char *comma = " ";
  189.         if (!filter.is_empty()){
  190.             fprintf (fout,"\"| %s\" ",filter.get());
  191.             comma = ",";
  192.         }
  193.         if (!file.is_empty()){
  194.             fprintf (fout,"%s:include:%s ",comma,file.get());
  195.             comma = ",";
  196.         }
  197.         int nb = values.getnb();
  198.         for (int i=0; i<nb; i++){
  199.             SSTRING *s = values.getitem(i);
  200.             if (!s->is_empty()){
  201.                 fprintf (fout,"%s%s ",comma,s->get());
  202.                 if (i > 0 && i % 4 == 0){
  203.                     fputc ('\n',fout);
  204.                     comma = "\t,";
  205.                 }else{
  206.                     comma = ",";
  207.                 }
  208.             }
  209.         }
  210.     }
  211.     fprintf (fout,"%s\n",comment.get());
  212. }
  213. /*
  214.     Is it a valid record or a comment
  215. */
  216. PUBLIC int ALIAS::is_valid()
  217. {
  218.     return !name.is_empty();
  219. }
  220.  
  221. /*
  222.     Edit an alias definition.
  223.     Return -1 if the user abort the edition (The record is left
  224.     unchanged then).
  225.     Return 0 if the user accepted the changes
  226.     Return 1 if the user request the deletion of this record
  227. */
  228. PUBLIC int ALIAS::edit()
  229. {
  230.     DIALOG dia;
  231.     dia.newf_str (MSG_U(F_ALIASNAME,"alias name"),name);
  232.     dia.newf_str (MSG_U(F_FILTER,"Filter program"),filter);
  233.     dia.newf_str (MSG_U(F_LISTFILE,"List file"),file);
  234.     /* #Specification: mailconf / aliases / limitation
  235.         The user interface present minimally 10 lines
  236.         for defining one alias value. A button ADD allows
  237.         the user to get more lines.
  238.     */
  239.     dia.newf_title ("","");
  240.     int i;
  241.     for (i=values.getnb(); i<10; i++) values.add (new SSTRING);
  242.     int vnb = values.getnb();
  243.     for (i=0; i<vnb; i++){
  244.         dia.newf_str ("",*values.getitem(i));
  245.     }
  246.     int no = 0;
  247.     int ret = -1;
  248.     while (1){
  249.         MENU_STATUS code = dia.edit (
  250.             MSG_U(T_ONEALIAS,"One alias definition")
  251.             ,MSG_U(I_ONEALIAS
  252.              ,"Use the button ADD to get more space\n"
  253.               "in case you are defining a mailing list\n")
  254.             ,help_aliases.getpath()
  255.             ,no
  256.             ,MENUBUT_ACCEPT|MENUBUT_CANCEL|MENUBUT_ADD|MENUBUT_DEL);
  257.         if (code == MENU_ESCAPE || code == MENU_CANCEL){
  258.             break;
  259.         }else if (code == MENU_DEL){
  260.             if (xconf_areyousure(MSG_U(Q_DELENTRY
  261.                 ,"Confirm deletion of this entry"))){
  262.                 ret = 1;
  263.                 break;
  264.             }
  265.         }else if (code == MENU_ADD){
  266.             int curnb = values.getnb();
  267.             for (i=0; i<10; i++) values.add (new SSTRING);
  268.             vnb = values.getnb();
  269.             for (i=curnb; i<vnb; i++){
  270.                 dia.newf_str ("",*values.getitem(i));
  271.             }
  272.         }else if (code == MENU_ACCEPT
  273.             && perm_rootaccess(MSG_U(P_EDITALIAS,"edit an alias"))){
  274.             if (name.is_empty()){
  275.                 no = 0;
  276.                 xconf_error (MSG_U(E_NONAME,"You must provide a name"));
  277.             }else if (!filter_ok()){
  278.                 no = 1;
  279.             }else if (!file_ok()){
  280.                 no = 1;
  281.             }else if (!filter.is_empty()
  282.                 || !file.is_empty()){
  283.                 ret = 0;
  284.                 break;
  285.             }else{
  286.                 for (i=0; i<vnb; i++){
  287.                     if (!values.getitem(i)->is_empty()){
  288.                         break;
  289.                     }
  290.                 }
  291.                 if (i == vnb){
  292.                     xconf_error (MSG_U(E_ALLEMPTY,"All values are empty"));
  293.                     no = 4;
  294.                 }else{
  295.                     ret = 0;
  296.                     break;
  297.                 }
  298.             }
  299.         }
  300.     }
  301.     if (ret == 0){
  302.         setmodified();
  303.     }else{
  304.         dia.restore();
  305.     }
  306.     return ret;
  307. }
  308.  
  309.  
  310. class ALIASES: public ARRAY{
  311.     /*~PROTOBEG~ ALIASES */
  312. public:
  313.     ALIASES (void);
  314. private:
  315.     void addline (char *buf);
  316. public:
  317.     void addnew (void);
  318. private:
  319.     int collect (const char **tb);
  320. public:
  321.     void edit (void);
  322.     ALIAS *getitem (int no);
  323.     int locate (const char *name);
  324.     void write (void);
  325.     /*~PROTOEND~ ALIASES */
  326. };
  327.  
  328. PUBLIC ALIAS *ALIASES::getitem(int no)
  329. {
  330.     return (ALIAS*)ARRAY::getitem(no);
  331. }
  332.  
  333. PRIVATE void ALIASES::addline (char *buf)
  334. {
  335.     if (buf[0] != '\0') add (new ALIAS(buf));
  336.     buf[0] = '\0';
  337. }
  338.  
  339. PUBLIC ALIASES::ALIASES()
  340. {
  341.     FILE *fin = f_aliases.fopen ("r");
  342.     if (fin != NULL){
  343.         char buf[10000];
  344.         char line[1000];
  345.         buf[0] = '\0';
  346.         while (fgets(line,sizeof(line)-1,fin)!=NULL){
  347.             strip_end (line);
  348.             if (line[0] == '\0'){
  349.                 addline (buf);
  350.             }else if (isspace(line[0])){
  351.                 strcat (buf,line);
  352.             }else{
  353.                 addline (buf);
  354.                 strcpy (buf,line);
  355.             }
  356.         }
  357.         addline(buf);
  358.         rstmodified();
  359.     }
  360. }
  361.  
  362.  
  363. /*
  364.     Write back /etc/aliases
  365. */
  366. PUBLIC void ALIASES::write ()
  367. {
  368.     FILE *fout = f_aliases.fopen ("w");
  369.     if (fout != NULL){
  370.         for (int i=0; i<getnb(); i++){
  371.             getitem(i)->write(fout);
  372.         }
  373.         fclose (fout);
  374.         rstmodified();
  375.         /* #Specification: mailconf / aliases / updating
  376.             Whenever the /etc/aliases is updated,
  377.             the command "/usr/lib/sendmail -bi"
  378.             is executed.
  379.         */
  380.         DAEMON *dae = daemon_find ("sendmail");
  381.         if (dae->is_managed()){
  382.             char cmd[200];
  383.             sprintf (cmd,"%s -bi",dae->getpath());
  384.             netconf_system (cmd);
  385.         }
  386.     }
  387. }
  388.  
  389. /*
  390.     Find an alias in the table.
  391.     Return -1 if not found.
  392.     Return the index otherwise.
  393. */
  394. PUBLIC int ALIASES::locate (const char *name)
  395. {
  396.     int ret = -1;
  397.     int nb = getnb();
  398.     for (int i=0; i<nb; i++){
  399.         /* #Specification: mailconf / user aliases / case sensitivity
  400.             Email aliases are case insensitive and linuxconf properly
  401.             check for a duplicate using stricmp().
  402.         */
  403.         if (stricmp(getitem(i)->getname(),name)==0){
  404.             ret = i;
  405.             break;
  406.         }
  407.     }
  408.     return ret;
  409. }
  410.  
  411. /*
  412.     Add a new record
  413. */
  414. PUBLIC void ALIASES::addnew()
  415. {
  416.     ALIAS *a = new ALIAS;
  417.     while (a->edit()==0){
  418.         if (locate(a->getname())!=-1){
  419.             xconf_error (MSG_U(E_DUPALIAS,"Duplicate alias, rejected"));
  420.         }else{
  421.             add (a);
  422.             write();
  423.             a = NULL;
  424.             break;
  425.         }
  426.     }
  427.     delete a;
  428. }
  429.  
  430. /*
  431.     Build the menuopt table for xconf_menu.
  432.     Return the number of line written.
  433.  
  434.     if tb is NULL, just count the number of line.
  435.     tb will be sorted.
  436. */    
  437. PRIVATE int ALIASES::collect(const char **tb)
  438. {
  439.     int count = 0;
  440.     int ii=0;
  441.     for (int i=0; i<nb; i++){
  442.         ALIAS *a = getitem(i);
  443.         if (a->is_valid()){
  444.             count++;
  445.             if (tb != NULL){
  446.                 tb[ii++] = " ";
  447.                 tb[ii++] = a->getname();
  448.             }
  449.         }
  450.     }
  451.     if (tb != NULL){
  452.         tb[ii] = NULL;
  453.         menuopt_sort (tb,count,1);
  454.     }
  455.     return count;
  456. }
  457.  
  458. /*
  459.     Edit, add, delete record in the /etc/aliases file
  460. */
  461.  
  462. PUBLIC void ALIASES::edit()
  463. {
  464.     int choice = 0;
  465.     while (1){
  466.         int nb = collect(NULL);
  467.         const char **menuopt
  468.             = (const char**)malloc(((nb*2)+1)*sizeof(char*));
  469.         collect(menuopt);
  470.         MENU_STATUS code = xconf_menu(
  471.             MSG_U(T_EDITALIASES,"Edit global mail aliases")
  472.             ,MSG_U(IEDITALIASES
  473.              ,"You are allowed to edit/add/deleted\n"
  474.               "system wide aliases for electronic mail")
  475.             ,help_aliases
  476.             ,NULL
  477.             ,NULL
  478.             ,NULL
  479.             ,MSG_U(I_NEWALIAS,"new aliases")
  480.             ,menuopt
  481.             ,choice);
  482.         ALIAS *item = NULL;
  483.         if (choice >=0 && choice < nb){
  484.             item = getitem(locate(menuopt[choice*2+1]));
  485.         }
  486.         free ((char**)menuopt);
  487.         if (code == MENU_ESCAPE || code == MENU_QUIT){
  488.             break;
  489.         }else if (code == MENU_OK){
  490.             if (item != NULL){
  491.                 int ok = item->edit();
  492.                 if (ok != -1){
  493.                     if (ok == 1) remove_del (item);
  494.                     write();
  495.                 }
  496.             }
  497.         }else if (perm_rootaccess(MSG_U(P_WRITE,"write %s"),f_aliases.getpath())){
  498.             if (code == MENU_ADD){
  499.                 addnew();
  500.             }
  501.         }
  502.     }
  503. }
  504.  
  505. void aliases_edit()
  506. {
  507.     ALIASES al;
  508.     al.edit();
  509. }
  510.  
  511.